<?php
/**
 * This class is here to manage user authorization loggings. This should
 * handle any current open session information and deal with loading /
 * unloading the client's logging from cookies and passwords.
 */
class Session
{
    /**
     * @var int The ID of the user this represents
     */
    private $userID;

    /**
     * @var string The username of this user
     */
    private $username;

    /**
     * @var string The encrypted password of the user
     */
    private $password;

    /**
     * TODO: Make the session ID
     * @var int The SessionID of the user
     */
    //private $sessionID;

    private static $instance;

    /**
     * @var User The user object from the DOM
     */
    public $user;

    /**
     * Default constructor, ensure that we retrieve the values of the username
     * and password from the client's cookies, and if the have username and
     * password values, ensure that we authenticate the values and test them
     * against the database values.
     */
    public function __construct()
    {
        $this->username = isset($_COOKIE["shumediausername"]) ? 
                          $_COOKIE["shumediausername"] : NULL;
        $this->password = isset($_COOKIE["shumediapassword"]) ? 
                          $_COOKIE["shumediapassword"] : NULL;
        
        if ($this->authenticateSession())
        {
            $DOM = DataObjectManager::inst();
            $this->user = $DOM->fetchDataObject("User", $this->username);
            $this->userID = $this->user->id;
        }
    }

    /**
     * Removes all of the cookies from the user's browser.
     */
    public function deleteCookies()
    {
        setcookie("shumediausername", "", time() - 3600, "/");
        setcookie("shumediapassword", "", time() - 3600, "/");
        $this->user = null;
        $this->userID = null;
        $this->username = null;
        $this->password = null;
    }

    /**
     * Encrypts the user's password and saves it
     *
     * @param string $username The user's username
     * @param string $password The user's real password (unencrypted)
     */
    public function writeCookies($username, $password)
    {
        $rc4 = RC4Encryption::inst();
        $password = $rc4->encrypt($password);
        $this->username = $username;
        $this->password = $password;
        setcookie("shumediausername", $this->username, time() + 216000, '/');
        setcookie("shumediapassword", $this->password, time() + 216000, '/');
    }

    /**
     * Tests to see if a user is authenticated from the given user and password
     * values.
     *
     * @return boolean Whether or not the user is authenticated
     */
    public function authenticateSession()
    {
        $DOM = DataObjectManager::inst();
        if (! isset($this->username) || ! isset($this->password))
        {
            return false;
        }

        //$user = false;
        $user = $DOM->fetchDataObject("User", $this->username);
        if (!$user)
        {
            return false;
        }
        if ($user->password == $this->password)
        {
            $this->user = $user;
            return true;
        }

        return false;
    }

    /**
     * This function ensures that we return the singelton static object of
     * this class. There should only ever be a single record of this objet
     * held by the class itself. This should be called as a static function
     * via the :: operator.
     *
     * @return Session The singleton session object of the user
     */
    public static function inst()
    {
        if (! isset(self::$instance))
        {
            $c = __CLASS__;
            self::$instance = new $c();
        }
        return self::$instance;
    }

    /**
     * Retrieves the ID of the user currently logged in.
     *
     * @return int The ID of the staff of the person logged in. Not set if not
     *             authenticated.
     */
    public function getUserid()
    {
        return $this->userID;
    }
}

/**
 * This class enables us to use RC4 Encryption techniques on strings. This
 * is what we shall use for the password to encrypt / decrypt.
 */
class RC4Encryption
{
    

    /**
     * @var string The RC4 Encryption key
     */
    private $key;

    private static $instance;


    /**
     * Default constructor, ensure that we initialise the construct and
     * retrieve the configuration values.
     */
    public function __construct()
    {
        
        $config = Config::inst();
        $this->key = $config->RC4Key;
    }

    /**
     * Retrieves the singleton instance. If the instance is not assigned
     * then we will create a new instance and assign it to the static
     * variable.
     *
     * @return RC4Encryption The static singleton of this object
     */
    public static function inst()
    {
        if (! isset(self::$instance))
        {
            $c = __CLASS__;
            self::$instance = new $c();
        }
        return self::$instance;
    }

    /**
     * Encrypts a string using the RC4 Key. Using this function on an
     * encrypted string decrypts it.
     *
     * @param string $string The string to encrypt
     */
    public function encrypt($string)
    {
        $keylength = strlen($this->key);
        $s = Array();
        for($i = 0; $i < 256; $i++) {
            $s[$i] = $i;
        }
        for ($i = $j = 0; $i < 256; $i++) {
            $temp = 0;
            $j = ($j + ord($this->key[$i % $keylength]) + $s[$i]) & 255;

            $temp = $s[$i];
            $s[$i] = $s[$j];
            $s[$j] = $temp;
        }
        $i = $j = 0;
        $n = 0;
        $out = '';
        while($n < strlen($string)) {
            $i = ($i + 1) & 255;
            $j = ($j + $s[$i]) & 255;
            $temp = $s[$j];
            $s[$j] = $s[$i];
            $s[$i] = $temp;
            $out .= chr((ord($string[$n])) ^ ($s[($temp + $s[$j]) & 255]));
            $n++;
        }
        return $out;
    }
}

?>
